home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / proc / procExit.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  51KB  |  1,714 lines

  1. /*
  2.  * procExit.c --
  3.  *
  4.  *    Routines to terminate and detach processes, and to cause a 
  5.  *    process to wait for the termination of other processes.  This file
  6.  *    maintains a monitor to synchronize between exiting, detaching, and
  7.  *    waiting processes.  The monitor also synchronizes access to the
  8.  *    dead list.
  9.  *
  10.  * Copyright 1986, 1988 Regents of the University of California
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  *
  19.  *    Proc table fields managed by this monitor:
  20.  *
  21.  *        1) exitFlags is managed solely by this monitor.
  22.  *        2) When a process is about to exit the PROC_DYING flag is set
  23.  *           in the genFlags field.  Also PROC_NO_VM flag set before
  24.  *           freeing VM segments.
  25.  *        3) The only way a process can go to the exiting and dead states 
  26.  *           is through using routines in this file.
  27.  *
  28.  *    A process can be in one of several states:
  29.  *
  30.  *    PROC_READY:    It is ready to execute when a CPU becomes available.
  31.  *            The PCB is attached to the Ready list.
  32.  *    PROC_RUNNING:    It is currently executing on a CPU.
  33.  *            The PCB is in the list of running processes.
  34.  *    PROC_WAITING:    It is waiting for an event to occur. 
  35.  *            The PCB is attached to an event-specific list of 
  36.  *            waiting processes.
  37.  *    PROC_EXITING:    It has finished executing but the PCB is kept around
  38.  *            until the parent waits for it via Proc_Wait or dies
  39.  *            via Proc_Exit.
  40.  *    PROC_DEAD:    It has been waited on and the PCB is attached to 
  41.  *            the Dead list.
  42.  *    PROC_SUSPENDED  It is suspended from executing.
  43.  *    PROC_UNUSED:    There is no process using this PCB entry.
  44.  *
  45.  *    In addition, the process may have the following attributes:
  46.  *
  47.  *    PROC_DETACHED:    It is detached from its parent.
  48.  *    PROC_WAITED_ON:    It is detached from its parent and its parent
  49.  *            knows about it. This attribute implies PROC_DETACHED
  50.  *            has been set.
  51.  *    PROC_SUSPEND_STATUS:
  52.  *            It is suspended and its parent has not waited on it
  53.  *            yet.  In this case it isn't detached.
  54.  *    PROC_RESUME_STATUS:
  55.  *            It has been resumed and its parent has not waited on
  56.  *            it yet.  In this case it isn't detached.
  57.  *
  58.  *    These attributes are set independently of the process states.
  59.  *
  60.  *    The routines in this file deal with transitions from the
  61.  *    RUNNING state to the EXITING and DEAD states and methods to 
  62.  *    detach a process.
  63.  *
  64.  *  State and Attribute Transitions:
  65.  *    The following tables show how a process changes attributes and states.
  66.  *
  67.  *
  68.  *   Legend:
  69.  *    ATTRIBUTE1 -> ATTRIBUTE2:
  70.  *    ---------------------------------------------------------------------
  71.  *      who        "routine it called to change attribute"    comments
  72.  *
  73.  *
  74.  *
  75.  *    Attached  -> Detached
  76.  *    ---------------------------------------------------------------------
  77.  *     current process    Proc_Detach
  78.  *
  79.  *    Detached -> Detached and Waited on
  80.  *    ---------------------------------------------------------------------
  81.  *     parent         Proc_Wait    WAITED_ON attribute set when
  82.  *                        parent finds child is detached.
  83.  *
  84.  *    Attached or Detached -> Detached and Waited on
  85.  *    ---------------------------------------------------------------------
  86.  *     parent            Proc_ExitInt    parent exiting, child detached.
  87.  *
  88.  *
  89.  *
  90.  *
  91.  *   Legend:
  92.  *    STATE1 -> STATE2:    (attributes before transition)
  93.  *    ---------------------------------------------------------------------
  94.  *      who        "routine it called to change state"     comments
  95.  *
  96.  *
  97.  *    RUNNING -> EXITING:    (attached or detached but not waited on)
  98.  *    RUNNING -> DEAD:    (detached and waited on)
  99.  *    ---------------------------------------------------------------------
  100.  *     current process    Proc_Exit    normal termination.
  101.  *     kernel            Proc_ExitInt    invalid process state found or
  102.  *                        process got a signal
  103.  *
  104.  *    EXITING -> DEAD:    (attached or detached or detached and waited on)
  105.  *    ---------------------------------------------------------------------
  106.  *     last family member to exit    Proc_ExitInt    
  107.  *     parent            Proc_Wait    parent waiting for child to exit
  108.  *     parent            Proc_ExitInt    parent exiting but did not 
  109.  *                        wait on child.
  110.  *
  111.  *    DEAD -> UNUSED:
  112.  *    ---------------------------------------------------------------------
  113.  *      The Reaper        Proc_Reaper     kernel process to clean the
  114.  *                        dead list. 
  115.  */
  116.  
  117. #ifndef lint
  118. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procExit.c,v 9.25 92/06/01 14:38:03 kupfer Exp $ SPRITE (Berkeley)";
  119. #endif /* not lint */
  120.  
  121. #include <sprite.h>
  122. #include <mach.h>
  123. #include <status.h>
  124. #include <proc.h>
  125. #include <procInt.h>
  126. #include <procMigrate.h>
  127. #include <migrate.h>
  128. #include <sync.h>
  129. #include <sched.h>
  130. #include <list.h>
  131. #include <sys.h>
  132. #include <vm.h>
  133. #include <prof.h>
  134. #include <dbg.h>
  135. #include <stdlib.h>
  136. #include <rpc.h>
  137. #include <sig.h>
  138. #include <stdio.h>
  139. #include <vmMach.h>
  140. #include <recov.h>
  141. #include <sysSysCall.h>
  142.  
  143. static    Sync_Lock    exitLock = Sync_LockInitStatic("Proc:exitLock"); 
  144. #define    LOCKPTR &exitLock
  145.  
  146. static     INTERNAL ReturnStatus FindExitingChild _ARGS_((
  147.                     Proc_ControlBlock *parentProcPtr,
  148.                     Boolean returnSuspend, int numPids,
  149.                     Proc_PID *pidArray, 
  150.                     ProcChildInfo *infoPtr));
  151. static     INTERNAL void WakeupMigratedParent _ARGS_((Proc_PID pid));
  152. static     void     SendSigChild _ARGS_((ClientData data, 
  153.             Proc_CallInfo *callInfoPtr));
  154. static     Proc_State    ExitProcessInt _ARGS_((
  155.                 Proc_ControlBlock *exitProcPtr,
  156.                 Boolean    migrated, Boolean contextSwitch));
  157.  
  158. /*
  159.  * Shared memory.
  160.  */
  161. extern int vmShmDebug;
  162. #ifndef lint
  163. #define dprintf if (vmShmDebug) printf
  164. #else /* lint */
  165. #define dprintf printf
  166. #endif /* lint */
  167.  
  168. /*
  169.  * SIGNAL_PARENT
  170.  *
  171.  * Macro to send a SIG_CHILD message to the parent.
  172.  */
  173. #define SIGNAL_PARENT(parentProcPtr, funcName) \
  174.     if ((parentProcPtr)->genFlags & PROC_USER) { \
  175.     ReturnStatus    status; \
  176.     Proc_Lock(parentProcPtr); \
  177.     status = Sig_SendProc(parentProcPtr, SIG_CHILD, 0, (Address)0); \
  178.     Proc_Unlock(parentProcPtr); \
  179.     if (status != SUCCESS) { \
  180.         printf("Warning: %s: Could not signal parent, status<%x>", \
  181.                 funcName, status); \
  182.     } \
  183.     }
  184.  
  185.  
  186. /*
  187.  *----------------------------------------------------------------------
  188.  *
  189.  * Proc_Exit --
  190.  *
  191.  *    The current process has decided to end it all voluntarily.
  192.  *    Call an internal procedure to do the work.
  193.  *
  194.  * Results:
  195.  *    None.  This routine should NOT return!
  196.  *
  197.  * Side effects:
  198.  *    None.
  199.  *
  200.  *----------------------------------------------------------------------
  201.  */
  202.  
  203. void
  204. Proc_Exit(status)
  205.     int    status;        /* Exit status from caller. */
  206. {
  207.     Proc_ExitInt(PROC_TERM_EXITED, status, 0);
  208.  
  209.     /*
  210.      *  Proc_ExitInt should never return.
  211.      */
  212. }
  213.  
  214.  
  215. /*
  216.  *----------------------------------------------------------------------
  217.  *
  218.  * Proc_ExitInt --
  219.  *
  220.  *    Internal routine to handle the termination of a process.  It
  221.  *    determines the process that is exiting and then calls
  222.  *    ProcExitProcess to do the work. This routine does NOT return because
  223.  *    a context switch is performed.  If the process is foreign,
  224.  *    ProcRemoteExit is called to handle cleanup on the home node
  225.  *    of the process, then ProcExitProcess is called.
  226.  *
  227.  * Results:
  228.  *    None.
  229.  *
  230.  * Side effects:
  231.  *    None.
  232.  *
  233.  *----------------------------------------------------------------------
  234.  */
  235.  
  236. void
  237. Proc_ExitInt(reason, status, code)
  238.     int reason;    /* Why the process is dying: EXITED, SIGNALED, DESTROYED  */
  239.     int    status;    /* Exit status or signal # or destroy status */
  240.     int code;    /* Signal sub-status */
  241. {
  242.     register Proc_ControlBlock     *curProcPtr;
  243.  
  244.     curProcPtr = Proc_GetActualProc();
  245.     if (curProcPtr == (Proc_ControlBlock *) NIL) {
  246.     panic("Proc_ExitInt: bad procPtr.\n");
  247.     }
  248.  
  249.     if (curProcPtr->genFlags & PROC_FOREIGN) {
  250.     ProcRemoteExit(curProcPtr, reason, status, code);
  251.     }
  252.     if (curProcPtr->Prof_Scale != 0) {
  253.     Prof_Disable(curProcPtr);
  254.     }
  255.     if (curProcPtr->genFlags & PROC_DEBUGGED) {
  256.     /*
  257.      * If a process is being debugged then force it onto the debug
  258.      * list before allowing it to exit.
  259.      */
  260.     Proc_SuspendProcess(curProcPtr, TRUE, reason, status, code);
  261.     }
  262.  
  263.     if (sys_ErrorShutdown) {
  264.     /*
  265.      * Are shutting down the system because of an error.  In this case
  266.      * don't close anything down because we want to leave as much state
  267.      * around as possible.
  268.      */
  269.     Sched_ContextSwitch(PROC_DEAD);
  270.     }
  271.     ProcExitProcess(curProcPtr, reason, status, code, TRUE);
  272.  
  273.     panic("Proc_ExitInt: Exiting process still alive!!!\n");
  274. }
  275.  
  276.  
  277. /*
  278.  *----------------------------------------------------------------------
  279.  *
  280.  * ExitProcessInt --
  281.  *
  282.  *    Do monitor level exit stuff for the process.
  283.  *
  284.  * Results:
  285.  *    None.
  286.  *
  287.  * Side effects:
  288.  *    If the process doesn't context switch, it is left locked.
  289.  *
  290.  *----------------------------------------------------------------------
  291.  */
  292.  
  293. ENTRY static Proc_State
  294. ExitProcessInt(exitProcPtr, migrated, contextSwitch) 
  295.     register Proc_ControlBlock    *exitProcPtr;    /* The exiting process. */
  296.     Boolean            migrated;    /* TRUE => foreign process. */
  297.     Boolean            contextSwitch;    /* TRUE => context switch. */
  298. {
  299.     register    Proc_ControlBlock    *procPtr;
  300.     Proc_State                newState = PROC_UNUSED;
  301.     register Proc_PCBLink         *procLinkPtr;
  302.     Timer_Ticks                 ticks;
  303.  
  304.     LOCK_MONITOR;
  305.  
  306.  
  307.     Proc_Lock(exitProcPtr);
  308.  
  309.     exitProcPtr->genFlags |= PROC_DYING;
  310.  
  311.     if (exitProcPtr->genFlags & PROC_MIG_PENDING) {
  312.     /*
  313.      * Someone is waiting for this guy to migrate.  Let them know that
  314.      * the process is dying.
  315.      */
  316.     exitProcPtr->genFlags &= ~PROC_MIG_PENDING;
  317.     ProcMigWakeupWaiters();
  318.     }
  319.  
  320.     /*
  321.      *  If the parent is still around, add the user and kernel cpu usage
  322.      *  of this process to the parent's summary of children.
  323.      *  If we're detached, don't give this stuff to the parent
  324.      *  (it might not exist.)  Keep track of global usage if we're local.
  325.      */
  326.  
  327.     if (!(exitProcPtr->genFlags & PROC_FOREIGN)) {
  328.     if (!(exitProcPtr->exitFlags & PROC_DETACHED)) {
  329.         register Proc_ControlBlock     *parentProcPtr;
  330.  
  331.         parentProcPtr = Proc_GetPCB(exitProcPtr->parentID);
  332.         if (parentProcPtr != (Proc_ControlBlock *) NIL) {
  333.         Timer_AddTicks(exitProcPtr->kernelCpuUsage.ticks, 
  334.                    parentProcPtr->childKernelCpuUsage.ticks, 
  335.                    &(parentProcPtr->childKernelCpuUsage.ticks));
  336.         Timer_AddTicks(exitProcPtr->childKernelCpuUsage.ticks, 
  337.                    parentProcPtr->childKernelCpuUsage.ticks, 
  338.                    &(parentProcPtr->childKernelCpuUsage.ticks));
  339.         Timer_AddTicks(exitProcPtr->userCpuUsage.ticks, 
  340.                    parentProcPtr->childUserCpuUsage.ticks, 
  341.                    &(parentProcPtr->childUserCpuUsage.ticks));
  342.         Timer_AddTicks(exitProcPtr->childUserCpuUsage.ticks, 
  343.                    parentProcPtr->childUserCpuUsage.ticks, 
  344.                    &(parentProcPtr->childUserCpuUsage.ticks));
  345.         }
  346.     }
  347. #ifndef CLEAN
  348.     Timer_AddTicks(exitProcPtr->kernelCpuUsage.ticks,
  349.             exitProcPtr->userCpuUsage.ticks, &ticks);
  350.     ProcRecordUsage(ticks, PROC_MIG_USAGE_TOTAL_CPU);
  351.     /*
  352.      * Record usage for just the amount of work performed after the
  353.      * first eviction.
  354.      */
  355.     if (exitProcPtr->migFlags & PROC_WAS_EVICTED) {
  356.         if (proc_MigDebugLevel > 4) {
  357.         printf("ExitProcessInt: process %x was evicted.  Used %d ticks before eviction, %d total.\n",
  358.                exitProcPtr->processID,
  359.                exitProcPtr->preEvictionUsage.ticks,
  360.                ticks);
  361.         }
  362.         Timer_SubtractTicks(ticks, exitProcPtr->preEvictionUsage.ticks,
  363.                 &ticks);
  364.         ProcRecordUsage(ticks, PROC_MIG_USAGE_POST_EVICTION);
  365.         exitProcPtr->migFlags &= ~PROC_WAS_EVICTED;
  366.     }
  367. #endif /* CLEAN */
  368.     }
  369.  
  370.     /* 
  371.      * If the process is voluntarily exiting and system call profiling is 
  372.      * enabled, update the time for Proc_Exit.
  373.      */
  374.     if (contextSwitch && exitProcPtr->termReason == PROC_TERM_EXITED &&
  375.     sys_CallProfiling) {
  376.     Sys_RecordCallFinish(SYS_PROC_EXIT);
  377.     }
  378.     
  379.     /*
  380.      * Make sure there are no lingering interval timer callbacks associated
  381.      * with this process.
  382.      *
  383.      *  Go through the list of children of the current process to 
  384.      *  make them orphans. When the children exit, this will typically
  385.      *  cause them to go on the dead list directly.
  386.      */
  387.  
  388.     if (!migrated) {
  389.     ProcDeleteTimers(exitProcPtr);
  390.     while (!List_IsEmpty(exitProcPtr->childList)) {
  391.         procLinkPtr = (Proc_PCBLink *) List_First(exitProcPtr->childList);
  392.         procPtr = procLinkPtr->procPtr;
  393.         List_Remove((List_Links *) procLinkPtr);
  394.         if (procPtr->state == PROC_EXITING) {
  395.         /*
  396.          * The child is exiting waiting for us to wait for it.
  397.          */
  398.         procPtr->state = PROC_DEAD;
  399.         Proc_CallFunc(Proc_Reaper, (ClientData) procPtr, 0);
  400.         } else {
  401.         /*
  402.          * Detach the child so when it exits, it will be
  403.          * put on the dead list automatically.
  404.          */
  405.         procPtr->exitFlags = PROC_DETACHED | PROC_WAITED_ON;
  406.         }
  407.     }
  408.     }
  409.  
  410.     /*
  411.      * If the debugger is waiting for this process to return to the debug
  412.      * state wake it up so that it will realize that the process is dead.
  413.      */
  414.  
  415.     if (exitProcPtr->genFlags & PROC_DEBUG_WAIT) {
  416.     ProcDebugWakeup();
  417.     }
  418.  
  419.     /*
  420.      * If the process is still waiting on an event, this is an error.
  421.      * [For now, flag this error only for foreign processes in case this
  422.      * isn't really an error after all.]
  423.      */
  424.     if (migrated && (exitProcPtr->event != NIL)) {
  425.     if (proc_MigDebugLevel > 0) {
  426.         panic(
  427.         "ExitProcessInt: exiting process still waiting on event %x.\n",
  428.         exitProcPtr->event);
  429.     } else {
  430.         printf(
  431.           "%s ExitProcessInt: exiting process still waiting on event %x.\n",
  432.           "Warning:", exitProcPtr->event);
  433.     }
  434.     }
  435.  
  436.     /*
  437.      * If the current process is detached and waited on (i.e. an orphan) then
  438.      * one of two things happen.  If the process is a family head and its list
  439.      * of family members is not empty then the process is put onto the exiting
  440.      * list.  Otherwise the process is put onto the dead list since its 
  441.      * parent has already waited for it.
  442.      */
  443.  
  444.     if (((exitProcPtr->exitFlags & PROC_DETACHED) &&
  445.         (exitProcPtr->exitFlags & PROC_WAITED_ON)) || migrated) {
  446.     newState = PROC_DEAD;
  447.     Proc_CallFunc(Proc_Reaper,  (ClientData) exitProcPtr, 0);
  448.     } else {
  449.     Proc_ControlBlock     *parentProcPtr;
  450.  
  451. #ifdef DEBUG_PARENT_PID
  452.     int hostID;
  453.     
  454.     hostID = Proc_GetHostID(exitProcPtr->parentID);
  455.     if (hostID != rpc_SpriteID && hostID != 0) {
  456.         panic("ExitProcessInt: parent process (%x) is on wrong host.\n",
  457.           exitProcPtr->parentID);
  458.         goto done;
  459.     }
  460. #endif DEBUG_PARENT_PID
  461.     parentProcPtr = Proc_GetPCB(exitProcPtr->parentID);
  462.     if (parentProcPtr == (Proc_ControlBlock *) NIL) {
  463.         panic("ExitProcessInt: no parent process (pid == %x)\n",
  464.           exitProcPtr->parentID);
  465.         goto done;
  466.     }
  467.     if (parentProcPtr->state != PROC_MIGRATED) {
  468.         Sync_Broadcast(&parentProcPtr->waitCondition);
  469. #ifdef notdef
  470.         SIGNAL_PARENT(parentProcPtr, "ExitProcessInt");
  471. #endif
  472.     } else {
  473.         WakeupMigratedParent(parentProcPtr->processID);
  474.     }
  475.     /*
  476.      * Signal the parent later on, when not holding the exit monitor
  477.      * lock.
  478.      */
  479.     Proc_CallFunc(SendSigChild, (ClientData)exitProcPtr->parentID, 0);
  480.  
  481.  
  482.     newState = PROC_EXITING;
  483.     }
  484. done:
  485.     if (contextSwitch) {
  486.     Proc_Unlock(exitProcPtr);
  487.     UNLOCK_MONITOR_AND_SWITCH(newState);
  488.     panic("ExitProcessInt: Exiting process still alive\n");
  489.     } else {
  490.     UNLOCK_MONITOR;
  491.     }
  492.     return(newState);
  493. }
  494.  
  495.  
  496. /*
  497.  *----------------------------------------------------------------------
  498.  *
  499.  * ProcExitProcess --
  500.  *
  501.  *    Internal routine to handle the termination of a process, due
  502.  *    to a normal exit, a signal or because the process state was
  503.  *    inconsistent.  The file system state associated with the process 
  504.  *    is invalidated. Any children of the process will become detatched.
  505.  *
  506.  * Results:
  507.  *    None.
  508.  *
  509.  * Side effects:
  510.  *    The PCB entry for the process is modified to clean-up FS
  511.  *    state. The specified process may be placed on the dead list.
  512.  *      If thisProcess is TRUE, a context switch is performed.  If not,
  513.  *    then the exit is being performed on behalf of another process;
  514.  *     the procPtr comes in locked and is unlocked as a side effect.
  515.  *
  516.  *----------------------------------------------------------------------
  517.  */
  518. void
  519. ProcExitProcess(exitProcPtr, reason, status, code, thisProcess) 
  520.     register Proc_ControlBlock     *exitProcPtr;    /* Exiting process. */
  521.     int             reason;        /* Why the process is dieing: 
  522.                          * EXITED, SIGNALED, 
  523.                          * DESTROYED  */
  524.     int                status;        /* Exit status, signal # or 
  525.                          * destroy status. */
  526.     int             code;        /* Signal sub-status */
  527.     Boolean             thisProcess;    /* TRUE => context switch */
  528. {
  529.     register Boolean         migrated;
  530.     Boolean            noVm;
  531.  
  532.     migrated = (exitProcPtr->genFlags & PROC_FOREIGN);
  533.  
  534.     /*
  535.      * Decrement the reference count on the environment.
  536.      */
  537.  
  538.     if (!migrated && exitProcPtr->environPtr != (Proc_EnvironInfo *) NIL) {
  539.     ProcDecEnvironRefCount(exitProcPtr->environPtr);
  540.     }
  541.  
  542.     /*
  543.      * The process is already locked if it comes in on behalf of someone
  544.      * else.
  545.      */
  546.     if (thisProcess) {
  547.     Proc_Lock(exitProcPtr);
  548.     }
  549.     if (exitProcPtr->genFlags & PROC_NO_VM) {
  550.     noVm = TRUE;
  551.     } else {
  552.     noVm = FALSE;
  553.     exitProcPtr->genFlags |= PROC_NO_VM;
  554.     }
  555.     Proc_Unlock(exitProcPtr);
  556.  
  557.     /*
  558.      * We have to do the Fs_CloseState in two phases:
  559.      *
  560.      * We must close pseudo-devices before destroying vm.
  561.      * Otherwise there is a race (hit by migd) when a pseudo-device
  562.      * is destroyed because data may be sent to the pseudo-device after
  563.      * it loses its vm but before it is removed from the file system.
  564.      * We will then crash because it has no vm for the data.
  565.      *
  566.      * We need to close swap files after deleting all the VM segments.
  567.      * Otherwise we die if a COW segment has swapped-out data.  The
  568.      * problem is we get the data from swap when we delete the segment.
  569.      * Thus we must delete the segment before we close down the swap files.
  570.      * --Ken Shirriff 10/90
  571.      */
  572.  
  573.     if (exitProcPtr->fsPtr != (struct Fs_ProcessState *) NIL) {
  574.     Fs_CloseState(exitProcPtr,0);
  575.     }
  576.  
  577.     /*
  578.      * Free up virtual memory resources, unless they were already freed.
  579.      */
  580.  
  581. #ifdef sun4
  582.     Mach_FlushWindowsToStack();
  583.     VmMach_FlushCurrentContext();
  584. #endif
  585.     if ((exitProcPtr->genFlags & PROC_USER) && !noVm) {
  586.     int i=0;
  587.     while (exitProcPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  588.  
  589.         if (exitProcPtr->vmPtr->sharedSegs == (List_Links *)NULL) {
  590.         dprintf("ProcExitProcess: warning: sharedSegs == NULL\n");
  591.         break;
  592.         }
  593.           i++;
  594.           if (i>20) {
  595.           dprintf("ProcExitProcess: procExit: segment loop!\n");
  596.           break;
  597.           }
  598.           if (exitProcPtr->vmPtr->sharedSegs==(List_Links *)NULL) {
  599.           printf("ProcExitProcess: Danger: null sharedSegs list\n");
  600.           break;
  601.           }
  602.           if (List_IsEmpty(exitProcPtr->vmPtr->sharedSegs)) {
  603.           printf("ProcExitProcess: Danger: empty sharedSegs list\n");
  604.           break;
  605.           }
  606.           if (List_First(exitProcPtr->vmPtr->sharedSegs)==
  607.               (List_Links *)NULL) {
  608.           break;
  609.           }
  610.           Vm_DeleteSharedSegment(exitProcPtr, (Vm_SegProcList *)
  611.             List_First(exitProcPtr->vmPtr->sharedSegs));
  612.       }
  613.     for (i = VM_CODE; i <= VM_STACK; i++) {
  614.         Vm_SegmentDelete(exitProcPtr->vmPtr->segPtrArray[i], exitProcPtr);
  615.         exitProcPtr->vmPtr->segPtrArray[i] = (Vm_Segment *)NIL;
  616.     }
  617.     }
  618.  
  619.     if (exitProcPtr->fsPtr != (struct Fs_ProcessState *) NIL) {
  620.     Fs_CloseState(exitProcPtr,1);
  621.     }
  622.  
  623.     /*
  624.      * Remove the process from its process family.  (Note, 
  625.      * migrated processes have family information on the home node.)
  626.      */
  627.     if (!migrated) {
  628.     ProcFamilyRemove(exitProcPtr);
  629.     }
  630.  
  631.     /*
  632.      *  The following information is kept in case the parent
  633.      *    calls Proc_Wait to wait for this process to terminate.
  634.      */
  635.  
  636.     exitProcPtr->termReason    = reason;
  637.     exitProcPtr->termStatus    = status;
  638.     exitProcPtr->termCode    = code;
  639.  
  640.     /* If we were created with a vfork, then wake the parent up */
  641.     if (exitProcPtr->genFlags & PROC_VFORKCHILD) {
  642.     Proc_VforkWakeup(exitProcPtr);
  643.     }
  644.  
  645.     exitProcPtr->state = ExitProcessInt(exitProcPtr, migrated, thisProcess);
  646.  
  647.     Proc_Unlock(exitProcPtr);
  648. }
  649.  
  650.  
  651. /*
  652.  *----------------------------------------------------------------------
  653.  *
  654.  * Proc_Reaper --
  655.  *
  656.  *    Cleans up the state information kept in the PCB for a dead process.
  657.  *    Processes get put on the dead list after they exit and someone has 
  658.  *    called Proc_Wait to wait for them. Detached processes
  659.  *    are put on the dead list when they call Proc_Exit or Proc_ExitInt.
  660.  *
  661.  * Results:
  662.  *    None.
  663.  *
  664.  * Side effects:
  665.  *    Virtual memory state for processes on the list is deallocated.
  666.  *
  667.  *----------------------------------------------------------------------
  668.  */
  669.  
  670. /* ARGSUSED */
  671. ENTRY void
  672. Proc_Reaper(data, callInfoPtr)
  673.     ClientData                data;        /* procPtr */
  674.     Proc_CallInfo            *callInfoPtr;
  675. {
  676.     register    Proc_ControlBlock     *procPtr = (Proc_ControlBlock *) data;
  677.     LOCK_MONITOR;
  678.     /*
  679.      * On a multiprocess there are two cases where we can't reap the process
  680.      * right away.  1 - the dying process may not have context switched
  681.      * into the DEAD state.  2 - the dying process's kernel stack may
  682.      * be used by a processor in the IdleLoop().  In either of these
  683.      * cases we reschedule ourselves for a second later.
  684.      */
  685.     if ((procPtr->state != PROC_DEAD) ||
  686.     (procPtr->schedFlags & SCHED_STACK_IN_USE)) {
  687.     callInfoPtr->interval = timer_IntOneSecond;
  688.     UNLOCK_MONITOR;
  689.     return;
  690.     } else {
  691.     callInfoPtr->interval = 0;
  692.     }
  693. #ifdef notdef
  694.     /*
  695.      * Next wait for the process's stack to become free.  On a multiprocessor
  696.      * a DEAD processes stack may be used to field interrupt by a processor
  697.      * until another process becomes ready.
  698.      */
  699.     while (procPtr->schedFlags & SCHED_STACK_IN_USE) {
  700.     UNLOCK_MONITOR;
  701.     Sync_WaitTime(time_OneSecond);
  702.     LOCK_MONITOR;
  703.     }
  704.     /*
  705.      * Since the SCHED_STACK_IN_USE is removed from a process before the
  706.      * context switch from that processor occurs we need to syncronize 
  707.      * with the scheduler.  Context switching on to the READY queue will
  708.      * cause such a syncronization.
  709.      */
  710.     Sched_ContextSwitch(PROC_READY);
  711. #endif
  712.     /*
  713.      * At this point a migrated process is not in the PROC_MIGRATED
  714.      * state since it's been moved to the PROC_DEAD state.  
  715.      * Migrated processes don't have a local machine-dependent state
  716.      * hanging off them.  They also don't have a current context, but
  717.      * VmMach_FreeContext can handle that.
  718.      */
  719.     if (procPtr->machStatePtr != (Mach_State *) NIL) {
  720.     Mach_FreeState(procPtr);
  721.     }
  722.     VmMach_FreeContext(procPtr);
  723.  
  724.     ProcFreePCB(procPtr);
  725.  
  726.     UNLOCK_MONITOR;
  727. }
  728.  
  729.  
  730. /*
  731.  *----------------------------------------------------------------------
  732.  *
  733.  * Proc_DetachInt --
  734.  *
  735.  *    The given process is detached from its parent.
  736.  *
  737.  * Results:
  738.  *    None.
  739.  *
  740.  * Side effects:
  741.  *    PROC_DETACHED flags set in the exitFlags field for the process.
  742.  *
  743.  *----------------------------------------------------------------------
  744.  */
  745.  
  746. ENTRY void
  747. Proc_DetachInt(procPtr)
  748.     register    Proc_ControlBlock    *procPtr;
  749. {
  750.     Proc_ControlBlock     *parentProcPtr;
  751.  
  752.     LOCK_MONITOR;
  753.  
  754.     /*
  755.      * If the process is already detached, there's no point to do it again.
  756.      * The process became detached by calling this routine or its parent
  757.      * has died.
  758.      */
  759.  
  760.     if (procPtr->exitFlags & PROC_DETACHED) {
  761.     UNLOCK_MONITOR;
  762.     return;
  763.     }
  764.  
  765.     procPtr->exitFlags |= PROC_DETACHED;
  766.  
  767.     /*
  768.      *  Wake up the parent in case it has called Proc_Wait to
  769.      *  wait for this child (or any other children) to terminate.
  770.      */
  771.  
  772.     parentProcPtr = Proc_GetPCB(procPtr->parentID);
  773.  
  774.     if (parentProcPtr->state == PROC_MIGRATED) {
  775.     WakeupMigratedParent(parentProcPtr->processID);
  776.     } else {
  777.     Sync_Broadcast(&parentProcPtr->waitCondition);
  778. #ifdef notdef
  779.     SIGNAL_PARENT(parentProcPtr, "Proc_DetachInt");
  780. #endif
  781.     }
  782.     /*
  783.      * Signal the parent later on, when not holding the exit monitor
  784.      * lock.
  785.      */
  786.     Proc_CallFunc(SendSigChild, (ClientData)parentProcPtr->processID, 0);
  787.  
  788.     UNLOCK_MONITOR;
  789. }
  790.  
  791.  
  792. /*
  793.  *----------------------------------------------------------------------
  794.  *
  795.  * Proc_InformParent --
  796.  *
  797.  *    Tell the parent of the given process that the process has changed
  798.  *    state.
  799.  *
  800.  * Results:
  801.  *    None.
  802.  *
  803.  * Side effects:
  804.  *    Status bit set in the exit flags.
  805.  *
  806.  *----------------------------------------------------------------------
  807.  */
  808. ENTRY void
  809. Proc_InformParent(procPtr, childStatus)
  810.     register Proc_ControlBlock    *procPtr;    /* Process whose parent to
  811.                          * inform of state change. */
  812.     int                childStatus;    /* PROC_SUSPEND_STATUS |
  813.                          * PROC_RESUME_STATUS */
  814. {
  815.     Proc_ControlBlock     *parentProcPtr;
  816.     Boolean migrated = FALSE;
  817.  
  818.     LOCK_MONITOR;
  819.  
  820.     /*
  821.      * If the process is already detached, then there is no parent to tell.
  822.      */
  823.     if (procPtr->exitFlags & PROC_DETACHED) {
  824.     UNLOCK_MONITOR;
  825.     return;
  826.     }
  827.  
  828.     /*
  829.      * Wake up the parent in case it has called Proc_Wait to
  830.      * wait for this child (or any other children) to terminate.  Also
  831.      * clear the suspended and waited on flag.
  832.      *
  833.      * For a migrated process, just send a signal no matter what, since it
  834.      * can go to an arbitrary node.  Also, do RPC's using a callback so
  835.      * the monitor lock isn't held during the RPC.  
  836.      */
  837.  
  838.     if (procPtr->genFlags & PROC_FOREIGN) {
  839.     migrated = TRUE;
  840.     }
  841.     if (!migrated) {
  842.     parentProcPtr = Proc_GetPCB(procPtr->parentID);
  843.     Sync_Broadcast(&parentProcPtr->waitCondition);
  844.     }
  845.     Proc_CallFunc(SendSigChild, (ClientData)procPtr->parentID, 0);
  846.     procPtr->exitFlags &= ~PROC_STATUSES;
  847.     procPtr->exitFlags |= childStatus;
  848.  
  849.     UNLOCK_MONITOR;
  850. }
  851.  
  852.  
  853. /*
  854.  *----------------------------------------------------------------------
  855.  *
  856.  * SendSigChild --
  857.  *
  858.  *    Send a SIG_CHILD signal to the given process.
  859.  *
  860.  * Results:
  861.  *    None.
  862.  *
  863.  * Side effects:
  864.  *    None.
  865.  *
  866.  *----------------------------------------------------------------------
  867.  */
  868.  
  869. /* ARGSUSED */
  870. static void
  871. SendSigChild(data, callInfoPtr)
  872.     ClientData        data;
  873.     Proc_CallInfo    *callInfoPtr;    /* passed in by callback routine */
  874. {
  875.     (void)Sig_Send(SIG_CHILD, SIG_NO_CODE, (Proc_PID)data, FALSE, (Address)0);
  876. }
  877.  
  878.  
  879. /*
  880.  *----------------------------------------------------------------------
  881.  *
  882.  * Proc_Detach --
  883.  *
  884.  *    The current process is detached from its parent. Proc_DetachInt called
  885.  *    to do most work.
  886.  *
  887.  * Results:
  888.  *    SUCCESS            - always returned.
  889.  *
  890.  * Side effects:
  891.  *    Statuses set in the proc table for the process.
  892.  *
  893.  *----------------------------------------------------------------------
  894.  */
  895.  
  896. ReturnStatus
  897. Proc_Detach(status)
  898.     int    status;        /* Detach status from caller. */
  899. {
  900.     register    Proc_ControlBlock     *procPtr;
  901.  
  902.     procPtr = Proc_GetEffectiveProc();
  903.     if (procPtr == (Proc_ControlBlock *) NIL) {
  904.     panic("Proc_Detach: procPtr == NIL\n");
  905.     }
  906.  
  907.     /*
  908.      *  The following information is kept in case the parent does a
  909.      *    Proc_Wait on this process.
  910.      */
  911.  
  912.     Proc_Lock(procPtr);
  913.     procPtr->termReason    = PROC_TERM_DETACHED;
  914.     procPtr->termStatus    = status;
  915.     procPtr->termCode    = 0;
  916.     Proc_Unlock(procPtr);
  917.  
  918.     Proc_DetachInt(procPtr);
  919.  
  920.     return(SUCCESS);
  921. }
  922.  
  923. static ReturnStatus     CheckPidArray _ARGS_((Proc_ControlBlock *curProcPtr,
  924.                 Boolean returnSuspend, int numPids,
  925.                 Proc_PID *pidArray, 
  926.                 Proc_ControlBlock **procPtrPtr));
  927. static ReturnStatus     LookForAnyChild _ARGS_((Proc_ControlBlock *curProcPtr,
  928.                 Boolean returnSuspend, 
  929.                 Proc_ControlBlock **procPtrPtr));
  930. extern ReturnStatus     DoWait _ARGS_((Proc_ControlBlock *curProcPtr,
  931.                 int    flags, int numPids, Proc_PID *newPidArray,
  932.                 ProcChildInfo *childInfoPtr));
  933.  
  934.  
  935. /*
  936.  *----------------------------------------------------------------------
  937.  *
  938.  * Proc_Wait --
  939.  *
  940.  *    Returns information about a child process that has changed state to
  941.  *    one of terminated, detached, suspended or running.  If the 
  942.  *    PROC_WAIT_FOR_SUSPEND flag is not set then info is only returned about
  943.  *    terminated and detached processes.  If the PROC_WAIT_BLOCK flag is
  944.  *    set then this function will wait for a child process to change state.
  945.  *
  946.  *    A terminated process is a process that has ceased execution because
  947.  *    it voluntarily called Proc_Exit or was involuntarily killed by 
  948.  *    a signal or was destroyed by the kernel due to an invalid stack. 
  949.  *    A detached process is process that has called Proc_Detach to detach 
  950.  *    itself from its parent. It continues to execute until it terminates.
  951.  *
  952.  * Results:
  953.  *    PROC_INVALID_PID -    a process ID in the pidArray was invalid.
  954.  *    SYS_INVALID_ARG -    the numPids argument specified a negative
  955.  *                number of pids in pidArray, or numPids
  956.  *                valid but pidArray was USER_NIL
  957.  *    SYS_ARG_NOACCESS -    an out parameter was inaccessible or
  958.  *                pidArray was inaccessible.
  959.  *
  960.  * Side effects:
  961.  *    Processes may be put onto the dead list after they have been waited on.
  962.  *
  963.  *----------------------------------------------------------------------
  964.  */
  965. ReturnStatus
  966. Proc_Wait(numPids, pidArray, flags, procIDPtr, reasonPtr, 
  967.       statusPtr, subStatusPtr, usagePtr)
  968.     int         numPids;    /* Number of entries in pidArray.  
  969.                       * 0 means wait for any child. */
  970.     Proc_PID         pidArray[];     /* Array of IDs of children to wait 
  971.                      * for. */
  972.     int         flags;        /* PROC_WAIT_BLOCK => wait if no 
  973.                      * children have exited, detached or
  974.                      * suspended.  
  975.                      * PROC_WAIT_FOR_SUSPEND => return 
  976.                      * status of suspended children. */
  977.  
  978.                 /* The following parameters may be USER_NIL. */
  979.     Proc_PID         *procIDPtr;     /* ID of the process that terminated. */
  980.     int         *reasonPtr;    /* Reason why the process exited. */
  981.     int         *statusPtr;    /* Exit status or termination signal 
  982.                      * number.  */
  983.     int         *subStatusPtr;    /* Additional signal status if the 
  984.                      * process died because of a signal. */
  985.     Proc_ResUsage    *usagePtr;    /* Resource usage summary for the 
  986.                      * process and its descendents. */
  987.  
  988. {
  989.     register Proc_ControlBlock     *curProcPtr;
  990.     ReturnStatus        status;
  991.     Proc_PID             *newPidArray = (Proc_PID *) NIL;
  992.     int             newPidSize;
  993.     ProcChildInfo        childInfo;
  994.     Proc_ResUsage         resUsage;
  995.     Boolean            migrated = FALSE;
  996.  
  997.     curProcPtr = Proc_GetCurrentProc();
  998.     if (curProcPtr == (Proc_ControlBlock *) NIL) {
  999.     panic("Proc_Wait: curProcPtr == NIL.\n");
  1000.     }
  1001.  
  1002.     if (curProcPtr->genFlags & PROC_FOREIGN) {
  1003.     migrated = TRUE;
  1004.     }
  1005.     
  1006.     /*
  1007.      *  If a list of pids to check was given, use it, otherwise
  1008.      *  look for any child that has changed state.
  1009.      */
  1010.     if (numPids < 0) {
  1011.     return(SYS_INVALID_ARG);
  1012.     } else if (numPids > 0) {
  1013.     if (pidArray == USER_NIL) {
  1014.         return(SYS_INVALID_ARG);
  1015.     } else {
  1016.         /*
  1017.          *  If pidArray is used, make it accessible. Also make sure that
  1018.          *  the pids are in the proper range.
  1019.          */
  1020.         newPidSize = numPids * sizeof(Proc_PID);
  1021.         newPidArray = (Proc_PID *) malloc(newPidSize);
  1022.         status = Vm_CopyIn(newPidSize, (Address) pidArray,
  1023.                    (Address) newPidArray);
  1024.         if (status != SUCCESS) {
  1025.         free((Address) newPidArray);
  1026.         return(SYS_ARG_NOACCESS);
  1027.         }
  1028.     }
  1029.     }
  1030.  
  1031.     if (!migrated) {
  1032.     status = DoWait(curProcPtr, flags, numPids, newPidArray, &childInfo);
  1033.     } else {
  1034.     status = ProcRemoteWait(curProcPtr, flags, numPids, newPidArray,
  1035.                 &childInfo);
  1036.     }
  1037.  
  1038.     if (numPids > 0) {
  1039.     free((Address) newPidArray);
  1040.     }
  1041.  
  1042.     if (status == SUCCESS) {
  1043.     if (procIDPtr != USER_NIL) {
  1044.         if (Vm_CopyOut(sizeof(Proc_PID), (Address) &childInfo.processID, 
  1045.         (Address) procIDPtr) != SUCCESS) {
  1046.         status = SYS_ARG_NOACCESS;
  1047.         }
  1048.     }
  1049.     if (reasonPtr != USER_NIL) {
  1050.         if (Vm_CopyOut(sizeof(int), (Address) &childInfo.termReason, 
  1051.         (Address) reasonPtr) != SUCCESS) {
  1052.         status = SYS_ARG_NOACCESS;
  1053.         }
  1054.     }
  1055.     if (statusPtr != USER_NIL) {
  1056.         if (Vm_CopyOut(sizeof(int), (Address) &childInfo.termStatus, 
  1057.         (Address) statusPtr) != SUCCESS) {
  1058.         status = SYS_ARG_NOACCESS;
  1059.         }
  1060.     }
  1061.     if (subStatusPtr != USER_NIL) {
  1062.         if (Vm_CopyOut(sizeof(int), (Address) &childInfo.termCode, 
  1063.         (Address) subStatusPtr) != SUCCESS) {
  1064.         status = SYS_ARG_NOACCESS;
  1065.         }
  1066.     }
  1067.     if (usagePtr != USER_NIL) {
  1068.         /*
  1069.          * Convert the usages from the internal Timer_Ticks format
  1070.          * into the external Time format.
  1071.          */
  1072.         Timer_TicksToTime(childInfo.kernelCpuUsage,
  1073.                   &resUsage.kernelCpuUsage);
  1074.         Timer_TicksToTime(childInfo.userCpuUsage,
  1075.                   &resUsage.userCpuUsage);
  1076.         Timer_TicksToTime(childInfo.childKernelCpuUsage, 
  1077.                   &resUsage.childKernelCpuUsage);
  1078.         Timer_TicksToTime(childInfo.childUserCpuUsage,
  1079.                   &resUsage.childUserCpuUsage);
  1080.         resUsage.numQuantumEnds = childInfo.numQuantumEnds;
  1081.         resUsage.numWaitEvents = childInfo.numWaitEvents;
  1082.         if (Vm_CopyOut(sizeof(Proc_ResUsage), (Address) &resUsage, 
  1083.                (Address) usagePtr) != SUCCESS) {
  1084.         status = SYS_ARG_NOACCESS;
  1085.         }
  1086.     }
  1087.     }
  1088.  
  1089.     return(status);
  1090. }
  1091.  
  1092.  
  1093. /*
  1094.  *----------------------------------------------------------------------
  1095.  *
  1096.  * DoWait --
  1097.  *
  1098.  *    Execute monitor level code for a Proc_Wait.  Return the information
  1099.  *    about the child that was found if any. 
  1100.  *
  1101.  * Results:
  1102.  *    PROC_INVALID_PID -    a process ID in the pidArray was invalid.
  1103.  *
  1104.  * Side effects:
  1105.  *    None.
  1106.  *
  1107.  *----------------------------------------------------------------------
  1108.  */
  1109.  
  1110. ENTRY ReturnStatus 
  1111. DoWait(curProcPtr, flags, numPids, newPidArray, childInfoPtr)
  1112.     register    Proc_ControlBlock    *curProcPtr;    /* Parent process. */
  1113.             /* PROC_WAIT_BLOCK => wait if no children have changed
  1114.              *               state.
  1115.              * PROC_WAIT_FOR_SUSPEND => return status of suspended
  1116.              *                children. */
  1117.     int                 flags;    
  1118.     int                    numPids;    /* Number of pids in
  1119.                              * newPidArray. */
  1120.     Proc_PID                 *newPidArray;    /* Array of pids. */
  1121.     ProcChildInfo            *childInfoPtr;    /* Place to store child
  1122.                              * information. */
  1123. {
  1124.     ReturnStatus    status;
  1125.  
  1126.     LOCK_MONITOR;
  1127.  
  1128.     while (TRUE) {
  1129.     /*
  1130.      * If a pid array was given, check the array to see if someone on it
  1131.      * has changed state. Otherwise, see if any child has done so.
  1132.      */
  1133.     status = FindExitingChild(curProcPtr, flags & PROC_WAIT_FOR_SUSPEND,
  1134.                 numPids, newPidArray, childInfoPtr);
  1135.  
  1136.     /* 
  1137.      * If someone was found or there was an error, break out of the loop
  1138.      * because we are done. FAILURE means no one was found.
  1139.      */
  1140.     if (status != FAILURE) {
  1141.         break;
  1142.     }
  1143.  
  1144.     /*
  1145.      *  If the search doesn't yields a child, we go to sleep waiting 
  1146.      *  for a process to wake us up if it exits or detaches itself.
  1147.      */
  1148.     if (!(flags & PROC_WAIT_BLOCK)) {
  1149.         /*
  1150.          * Didn't find anyone to report on.
  1151.          */
  1152.         status = PROC_NO_EXITS;
  1153.         break;
  1154.  
  1155.     } else {    
  1156.         /*
  1157.          *  Since the current process is local, it will go to sleep
  1158.          *  on its waitCondition.  A child will wakeup the process by
  1159.          *  doing a wakeup on its parent's waitCondition.
  1160.          *
  1161.          *  This technique reduces the number of woken processes
  1162.          *  compared to having every process wait on the same
  1163.          *  event (e.g. exiting list address) when it goes to
  1164.          *  sleep.  When we wake up, the search will start again.
  1165.          *
  1166.          * Check for the signal being SIG_CHILD, in which case
  1167.          * don't abort the Proc_Wait.  This can happen if the parent and
  1168.          * the child are on different hosts so the Sync_Wait is aborted
  1169.          * by the signal rather than a wakeup.  (The parent should handle
  1170.          * SIGCHLD better, but it might not, thereby missing the child's
  1171.          * change in state.)
  1172.          */
  1173.         if (Sync_Wait(&curProcPtr->waitCondition, TRUE)) {
  1174.         if (Sig_Pending(curProcPtr) != Sig_NumberToMask(SIG_CHILD)) {
  1175.             status = GEN_ABORTED_BY_SIGNAL;
  1176.             break;
  1177.         }
  1178.         }
  1179.     }
  1180.     }
  1181.  
  1182.     UNLOCK_MONITOR;
  1183.     return(status);
  1184. }
  1185.  
  1186.  
  1187. /*
  1188.  * ----------------------------------------------------------------------------
  1189.  *
  1190.  * ProcRemoteWait --
  1191.  *
  1192.  *    Perform an RPC to do a Proc_Wait on the home node of the given
  1193.  *    process.  Transfer the information for a child that has changed state,
  1194.  *    if one exists, and set up the information for a remote
  1195.  *    wait if the process wishes to block waiting for a child.  Note
  1196.  *    that this routine is unsynchronized, since monitor locking is
  1197.  *    performed on the home machine of the process.
  1198.  *
  1199.  * Results:
  1200.  *    The status from the remote Proc_Wait (or RPC status) is returned.
  1201.  *
  1202.  * Side effects:
  1203.  *    None.
  1204.  *
  1205.  * ----------------------------------------------------------------------------
  1206.  */
  1207.  
  1208. ReturnStatus
  1209. ProcRemoteWait(procPtr, flags, numPids, pidArray, childInfoPtr)
  1210.     Proc_ControlBlock    *procPtr;
  1211.     int            flags;
  1212.     int            numPids;
  1213.     Proc_PID        pidArray[];
  1214.     ProcChildInfo    *childInfoPtr;
  1215. {
  1216.     ProcRemoteWaitCmd cmd;
  1217.     Rpc_Storage storage;
  1218.     ReturnStatus status;
  1219.     int numTries;
  1220.  
  1221.     if (proc_MigDebugLevel > 3) {
  1222.     printf("ProcRemoteWait(%x, ...) called.\n", procPtr->processID);
  1223.     }
  1224.  
  1225.     /*
  1226.      * Check to make sure the home node is up, and kill the process if
  1227.      * it isn't.  The call to exit never returns.
  1228.      */
  1229.     status = Recov_IsHostDown(procPtr->peerHostID);
  1230.     if (status != SUCCESS) {
  1231.     if (proc_MigDebugLevel > 0) {
  1232.         printf("Proc_DoRemoteCall: host %d is down; killing process %x.\n",
  1233.                procPtr->peerHostID, procPtr->processID);
  1234.     }
  1235.     Proc_ExitInt(PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0);
  1236.     /*
  1237.      * This point should not be reached, but the N-O-T-R-E-A-C-H-E-D
  1238.      * directive causes a complaint when there's code after it.
  1239.      */
  1240.     panic("ProcRemoteWait: Proc_ExitInt returned.\n");
  1241.     return(PROC_NO_PEER);
  1242.     }
  1243.     /*
  1244.      * Set up the invariant fields of the rpc call, since we may make
  1245.      * multiple calls after waiting.
  1246.      */
  1247.     
  1248.     cmd.pid = procPtr->peerProcessID;
  1249.     cmd.numPids = numPids;
  1250.     cmd.flags = flags;
  1251.     cmd.token = NIL;
  1252.  
  1253.     storage.requestParamPtr = (Address) &cmd;
  1254.     storage.requestParamSize = sizeof(ProcRemoteWaitCmd);
  1255.     storage.requestDataPtr = (Address) pidArray;
  1256.     storage.requestDataSize = numPids * sizeof(Proc_PID);
  1257.  
  1258.     while (TRUE) {
  1259.  
  1260.     storage.replyParamPtr = (Address) NIL;
  1261.     storage.replyParamSize = 0;
  1262.     storage.replyDataPtr = (Address) childInfoPtr;
  1263.     storage.replyDataSize = sizeof(ProcChildInfo);
  1264.  
  1265.     if (flags & PROC_WAIT_BLOCK) {
  1266.         Sync_GetWaitToken((Proc_PID *) NIL, &cmd.token);
  1267.     }
  1268.  
  1269.     /*
  1270.      * Set up for the RPC.
  1271.      */
  1272.     
  1273.     for (numTries = 0; numTries < PROC_MAX_RPC_RETRIES; numTries++) {
  1274.         status = Rpc_Call(procPtr->peerHostID, RPC_PROC_REMOTE_WAIT,
  1275.                   &storage);
  1276.         if (status != RPC_TIMEOUT) {
  1277.         break;
  1278.         }
  1279.         status = Proc_WaitForHost(procPtr->peerHostID);
  1280.         if (status != SUCCESS) {
  1281.         break;
  1282.         }
  1283.     }
  1284.  
  1285.     /*
  1286.      * If the status is FAILURE, no children have exited so far.  In
  1287.      * this case, we may want to sleep.
  1288.      */
  1289.     if (status != FAILURE) {
  1290.         break;
  1291.     }
  1292.  
  1293.     /*
  1294.      * If the search doesn't yield a child and we are supposed to block,
  1295.      * we go to sleep waiting for a process to wake us up if it
  1296.      * exits or detaches itself.
  1297.      */
  1298.  
  1299.     if (!(flags & PROC_WAIT_BLOCK)) {
  1300.         /*
  1301.          * Didn't find anyone to report on.
  1302.          */
  1303.         status = PROC_NO_EXITS;
  1304.         break;
  1305.  
  1306.     } else if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  1307.         status = GEN_ABORTED_BY_SIGNAL;
  1308.         break;
  1309.     }  
  1310.     }
  1311.  
  1312.     if (status == PROC_NO_PEER) {
  1313.     (void) Sig_Send(SIG_KILL, (int) PROC_NO_PEER, procPtr->processID,
  1314.             FALSE, (Address)0); 
  1315.     if (proc_MigDebugLevel > 1) {
  1316.         printf("%s killing process %x: home node's copy (pid %x) died.\n",
  1317.            "ProcRemoteWait", procPtr->processID,
  1318.            procPtr->peerProcessID);
  1319.     }
  1320.     } else if (proc_MigDebugLevel > 3) {
  1321.     printf("ProcRemoteWait returning status %x.\n", status);
  1322.     if (status == SUCCESS && proc_MigDebugLevel > 6) {
  1323.         printf("Child's id is %x, status %x.\n",
  1324.                childInfoPtr->processID, childInfoPtr->termStatus);
  1325.     }
  1326.     }
  1327.     return(status);
  1328. }
  1329.  
  1330.  
  1331. /*
  1332.  *----------------------------------------------------------------------
  1333.  *
  1334.  * ProcServiceRemoteWait --
  1335.  *
  1336.  *    Services the Proc_Wait command for a migrated process.  If
  1337.  *    there is an appropriate child, returns information about it (refer
  1338.  *    to Proc_Wait).  If not, returns    PROC_NO_EXITS.  If the migrated
  1339.  *    process specified that it should block, set up a remote wakeup
  1340.  *    for when a child changes state.
  1341.  *
  1342.  * Results:
  1343.  *    PROC_INVALID_PID -    a process ID in the pidArray is invalid.
  1344.  *    PROC_NO_EXITS    -    no children have changed state which have
  1345.  *                not already been waited upon.
  1346.  *
  1347.  * Side effects:
  1348.  *    Processes on the exiting list may be put on the dead list after 
  1349.  *    they have been waited on.  A remote wakeup may be established.
  1350.  *
  1351.  *----------------------------------------------------------------------
  1352.  */
  1353.  
  1354. ENTRY ReturnStatus
  1355. ProcServiceRemoteWait(curProcPtr, flags, numPids, pidArray, waitToken,
  1356.               childInfoPtr)
  1357.     register Proc_ControlBlock     *curProcPtr;
  1358.     int                flags;
  1359.     int numPids;    /* Number of entries in pidArray.  
  1360.              *  0 means wait for any child. */
  1361.     Proc_PID pidArray[]; /* Array of IDs of children to wait for. */
  1362.     int waitToken;      /* Token to use if blocking. */
  1363.     ProcChildInfo *childInfoPtr; /* Information to return about child. */
  1364.  
  1365. {
  1366.     ReturnStatus        status;
  1367.  
  1368.     LOCK_MONITOR;
  1369.  
  1370.     status = FindExitingChild(curProcPtr, flags & PROC_WAIT_FOR_SUSPEND,
  1371.                 numPids, pidArray, childInfoPtr);
  1372.     if (proc_MigDebugLevel > 3) {
  1373.     printf("pid %x got status %x from FindExitingChild\n",
  1374.            curProcPtr->processID, status);
  1375.     if (status == SUCCESS && proc_MigDebugLevel > 6) {
  1376.         printf("Child's id is %x, status %x.\n",
  1377.                childInfoPtr->processID, childInfoPtr->termStatus);
  1378.     }
  1379.     }
  1380.  
  1381.     /* 
  1382.      * FAILURE means no one was found, so set up a remote wakeup if needed.
  1383.      * Otherwise, just return the childInfo as it was set by FindExitingChild
  1384.      * and get out.
  1385.      */
  1386.     if (status == FAILURE) {
  1387.     if (flags & PROC_WAIT_BLOCK) {
  1388.         Sync_SetWaitToken(curProcPtr, waitToken);
  1389.     }
  1390.     } 
  1391.  
  1392.     UNLOCK_MONITOR;
  1393.     return(status);
  1394. }
  1395.  
  1396.  
  1397. /*
  1398.  *----------------------------------------------------------------------
  1399.  *
  1400.  *  FindExitingChild --
  1401.  *
  1402.  *    Find a child of the specified process who has changed state,
  1403.  *    subject to possible constraints (a list of process
  1404.  *    IDs to check).  If a process is found, send that process to the
  1405.  *    reaper if appropriate.
  1406.  *
  1407.  *    If numPids is 0, look for any child, else look for specific
  1408.  *    processes.
  1409.  *
  1410.  * Results:
  1411.  *    PROC_NO_CHILDREN -    There are no children of this process left
  1412.  *                to be waited on.
  1413.  *    FAILURE -        didn't find any child of interest.
  1414.  *    SUCCESS -        got one.
  1415.  *
  1416.  * Side effects:
  1417.  *    If a process is found, *childInfoPtr is set to contain the relevant
  1418.  *    information from the child.
  1419.  *
  1420.  *----------------------------------------------------------------------
  1421.  */
  1422.  
  1423. INTERNAL static ReturnStatus 
  1424. FindExitingChild(parentProcPtr, returnSuspend, numPids, pidArray, infoPtr)
  1425.     Proc_ControlBlock         *parentProcPtr;    /* Parent's PCB */
  1426.     Boolean            returnSuspend;    /* Return information about
  1427.                          * suspended or resumed
  1428.                          * children. */ 
  1429.     int             numPids;    /* Number of Pids in pidArray */
  1430.     Proc_PID             *pidArray;    /* Array of Pids to check */
  1431.     register ProcChildInfo    *infoPtr;    /* Place to return info */
  1432. {
  1433.     ReturnStatus status;
  1434.     Proc_ControlBlock *paramProcPtr;
  1435.     register Proc_ControlBlock *procPtr;
  1436.     
  1437.     if (numPids > 0) {
  1438.     status = CheckPidArray(parentProcPtr, returnSuspend, numPids, pidArray,
  1439.                    ¶mProcPtr);
  1440.     } else {
  1441.     status = LookForAnyChild(parentProcPtr, returnSuspend, ¶mProcPtr);
  1442.     }
  1443.     if (status == SUCCESS) {
  1444.     procPtr = paramProcPtr;
  1445.     if (procPtr->state == PROC_EXITING ||
  1446.         (procPtr->exitFlags & PROC_DETACHED)) {
  1447.         List_Remove((List_Links *) &(procPtr->siblingElement));
  1448.         infoPtr->termReason        = procPtr->termReason;
  1449.         if (procPtr->state == PROC_EXITING) {
  1450.         /*
  1451.          * Once an exiting process has been waited on it is moved
  1452.          * from the exiting state to the dead state.
  1453.          */
  1454.         procPtr->state = PROC_DEAD;
  1455.         Proc_CallFunc(Proc_Reaper,  (ClientData) procPtr, 0);
  1456.         } else {
  1457.         /*
  1458.          * The child is detached and running.  Set a flag to make sure
  1459.          * we don't find this process again in a future call to
  1460.          * Proc_Wait.
  1461.          */
  1462.         procPtr->exitFlags |= PROC_WAITED_ON;
  1463.         }
  1464.     } else {
  1465.         /*
  1466.          * The child was suspended or resumed.
  1467.          */
  1468.         if (procPtr->exitFlags & PROC_SUSPEND_STATUS) {
  1469.         procPtr->exitFlags &= ~PROC_SUSPEND_STATUS;
  1470.         infoPtr->termReason = PROC_TERM_SUSPENDED;
  1471.         } else if (procPtr->exitFlags & PROC_RESUME_STATUS) {
  1472.         procPtr->exitFlags &= ~PROC_RESUME_STATUS;
  1473.         infoPtr->termReason = PROC_TERM_RESUMED;
  1474.         }
  1475.     }
  1476.  
  1477.     infoPtr->processID        = procPtr->processID;
  1478.     infoPtr->termStatus        = procPtr->termStatus;
  1479.     infoPtr->termCode        = procPtr->termCode;
  1480.     infoPtr->kernelCpuUsage        = procPtr->kernelCpuUsage.ticks;
  1481.     infoPtr->userCpuUsage        = procPtr->userCpuUsage.ticks;
  1482.     infoPtr->childKernelCpuUsage    = procPtr->childKernelCpuUsage.ticks;
  1483.     infoPtr->childUserCpuUsage     = procPtr->childUserCpuUsage.ticks;
  1484.     infoPtr->numQuantumEnds        = procPtr->numQuantumEnds;
  1485.     infoPtr->numWaitEvents        = procPtr->numWaitEvents;
  1486.  
  1487.     Proc_Unlock(procPtr);
  1488.     }
  1489.  
  1490.     return(status);
  1491. }              
  1492.  
  1493.  
  1494. /*
  1495.  *----------------------------------------------------------------------
  1496.  *
  1497.  *  LookForAnyChild --
  1498.  *
  1499.  *    Search the process's list of children to see if any of 
  1500.  *    them have exited, become detached or been suspended or resumed.
  1501.  *    If no child is found, make sure there is a child who can wake us up.
  1502.  *
  1503.  * Results:
  1504.  *    PROC_NO_CHILDREN -    There are no children of this process left
  1505.  *                to be waited on.
  1506.  *    FAILURE -        didn't find any child of interest.
  1507.  *    SUCCESS -        got one.
  1508.  *
  1509.  * Side effects:
  1510.  *    None.
  1511.  *
  1512.  *----------------------------------------------------------------------
  1513.  */
  1514.  
  1515. INTERNAL static ReturnStatus
  1516. LookForAnyChild(curProcPtr, returnSuspend, procPtrPtr)
  1517.     register    Proc_ControlBlock    *curProcPtr;    /* Parent proc.*/
  1518.     Boolean                returnSuspend;    /* Return info about
  1519.                              * suspended children.*/    Proc_ControlBlock             **procPtrPtr;    /* Child proc. */
  1520. {
  1521.     register Proc_ControlBlock *procPtr;
  1522.     register Proc_PCBLink *procLinkPtr;
  1523.     Boolean foundValidChild = FALSE;
  1524.  
  1525.     /*
  1526.      *  Loop through the list of children, looking for the first child
  1527.      *  to have changed state. Ignore children that are detached
  1528.      *  and waited-on.
  1529.      */
  1530.  
  1531.     LIST_FORALL((List_Links *) curProcPtr->childList,
  1532.         (List_Links *) procLinkPtr) {
  1533.         procPtr = procLinkPtr->procPtr;
  1534.     /*
  1535.      *  It may be that one of our children is in the process of exiting.
  1536.      *  If it is marked as 'dying' but not 'exiting', then it has
  1537.      *  left the monitor (obvious because we're in the monitor now)
  1538.      *  but hasn't completed the context switch to the 'exiting' state.
  1539.      *  This can only happen if the child is on a different processor
  1540.      *  from ourself.  We'll wait for the child to become exiting since
  1541.      *  it will take at most the length of a context switch to finish.
  1542.      *  If we don't wait for this child we will miss the transition
  1543.      *  and potentially wait forever.
  1544.      */
  1545.     if (procPtr->genFlags & PROC_DYING) {
  1546.         while (procPtr->state != PROC_EXITING) {
  1547.         /*
  1548.          * Wait for the other processor to set the state to exiting.
  1549.          */
  1550.         }
  1551.     }
  1552.     if ((procPtr->state == PROC_EXITING) ||
  1553.         (procPtr->exitFlags & PROC_DETACHED) ||
  1554.         (returnSuspend && (procPtr->exitFlags & PROC_STATUSES))) {
  1555.         if (!(procPtr->exitFlags & PROC_WAITED_ON)) {
  1556.             *procPtrPtr = procPtr;
  1557.         Proc_Lock(procPtr);
  1558.             return(SUCCESS);
  1559.         }
  1560.     } else {
  1561.         foundValidChild = TRUE;
  1562.     }
  1563.     }
  1564.  
  1565.     if (foundValidChild) {
  1566.     return(FAILURE);
  1567.     }
  1568.     return(PROC_NO_CHILDREN);
  1569. }
  1570.  
  1571.  
  1572. /*
  1573.  *----------------------------------------------------------------------
  1574.  *
  1575.  *  CheckPidArray --
  1576.  *
  1577.  *    Search the process's array of children to see if any of them 
  1578.  *    have exited, become detached or been suspended or resumed.
  1579.  *
  1580.  * Results:
  1581.  *    FAILURE -        didn't find any child of interest.
  1582.  *    PROC_INVALID_PID -    a pid in the array was invalid.
  1583.  *    SUCCESS -        got one.
  1584.  *
  1585.  * Side effects:
  1586.  *    None.
  1587.  *
  1588.  *----------------------------------------------------------------------
  1589.  */
  1590.  
  1591.  
  1592. INTERNAL static ReturnStatus
  1593. CheckPidArray(curProcPtr, returnSuspend, numPids,  pidArray, procPtrPtr)
  1594.     register    Proc_ControlBlock    *curProcPtr;    /* Parent proc. */
  1595.     Boolean                returnSuspend;    /* Return information
  1596.                              * about suspended or
  1597.                              * resumed children. */
  1598.     int                    numPids;    /* Number of pids in 
  1599.                              * pidArray. */
  1600.     Proc_PID                *pidArray;    /* Array of pids to 
  1601.                              * check. */
  1602.     Proc_ControlBlock             **procPtrPtr;    /* Child proc. */
  1603. {
  1604.     register Proc_ControlBlock    *procPtr;
  1605.     int                i;
  1606.  
  1607.     /*
  1608.      * The user has specified a list of processes to wait for.
  1609.      * If a specified process is non-existent or is not a child of the
  1610.      * calling process return an error status.
  1611.      */
  1612.     for (i=0; i < numPids; i++) {
  1613.     procPtr = Proc_LockPID(pidArray[i]);
  1614.     if (procPtr == (Proc_ControlBlock *) NIL) {
  1615.         return(PROC_INVALID_PID);
  1616.     }
  1617.     if (!Proc_ComparePIDs(procPtr->parentID, curProcPtr->processID)) {
  1618.         Proc_Unlock(procPtr);
  1619.         return(PROC_INVALID_PID);
  1620.     }
  1621.     if ((procPtr->state == PROC_EXITING) ||
  1622.         (procPtr->exitFlags & PROC_DETACHED) ||
  1623.         (returnSuspend && (procPtr->exitFlags & PROC_STATUSES))) {
  1624.         if (!(procPtr->exitFlags & PROC_WAITED_ON)) {
  1625.         *procPtrPtr = procPtr;
  1626.         return(SUCCESS);
  1627.         }
  1628.     }
  1629.     Proc_Unlock(procPtr);
  1630.     } 
  1631.     return(FAILURE);
  1632. }
  1633.  
  1634.  
  1635. /*
  1636.  *----------------------------------------------------------------------
  1637.  *
  1638.  * Proc_NotifyMigratedWaiters --
  1639.  *
  1640.  *    Waits to find out about migrated processes that have performed
  1641.  *    Proc_Waits and then issues Sync_RemoteNotify calls to wake them
  1642.  *    up.  Uses a monitored procedure to access the shared list containing
  1643.  *    process IDs.
  1644.  *
  1645.  * Results:
  1646.  *    None.
  1647.  *
  1648.  * Side effects:
  1649.  *    RPCs are issued as children of migrated processes detach or die.
  1650.  *
  1651.  *----------------------------------------------------------------------
  1652.  */
  1653.  
  1654. /* ARGSUSED */
  1655. void
  1656. Proc_NotifyMigratedWaiters(data, callInfoPtr)
  1657.     ClientData        data;            /* pid */
  1658.     Proc_CallInfo    *callInfoPtr;        /* not used */
  1659. {
  1660.     Proc_PID             pid = (Proc_PID) data;
  1661.     register Proc_ControlBlock     *procPtr;
  1662.     Sync_RemoteWaiter         waiter;
  1663.     ReturnStatus         status;
  1664.  
  1665.     procPtr = Proc_LockPID(pid);
  1666.     if (procPtr == (Proc_ControlBlock *) NIL) {
  1667.     return;
  1668.     }
  1669.  
  1670.     waiter.hostID = procPtr->peerHostID;
  1671.     waiter.pid = procPtr->peerProcessID;
  1672.     waiter.waitToken =  procPtr->waitToken;
  1673.     Proc_Unlock(procPtr);
  1674.  
  1675.     if (proc_MigDebugLevel > 3) {
  1676.     printf("Proc_NotifyMigratedWaiters: notifying process %x.\n",
  1677.            waiter.pid);
  1678.     }
  1679.     status = Sync_RemoteNotify(&waiter);
  1680.     if (status != SUCCESS) {
  1681.     printf("Warning: received status %x notifying process.\n", status);
  1682.     }
  1683. }
  1684.  
  1685.  
  1686. /*
  1687.  *----------------------------------------------------------------------
  1688.  *
  1689.  * WakeupMigratedParent --
  1690.  *
  1691.  *    Call the function Proc_NotifyMigratedWaiters by starting a process
  1692.  *    on it.
  1693.  *
  1694.  * Results:
  1695.  *    None.
  1696.  *
  1697.  * Side effects:
  1698.  *    None.
  1699.  *
  1700.  *----------------------------------------------------------------------
  1701.  */
  1702.  
  1703. static INTERNAL void
  1704. WakeupMigratedParent(pid)
  1705.     Proc_PID pid;
  1706. {
  1707.  
  1708.     if (proc_MigDebugLevel > 3) {
  1709.     printf("WakeupMigratedParent: inserting process %x.\n", pid);
  1710.     }
  1711.     Proc_CallFunc(Proc_NotifyMigratedWaiters, (ClientData) pid, 0);
  1712. }
  1713.  
  1714.